//---------------------------------------------------------------------------
// CBufferedStream Class
// Author : Woo-Hyun Kim
// Email : woorung@nhncorp.com
// Date : Dec. 5, 2007
//---------------------------------------------------------------------------
#include "CBufferedStream.h"
//---------------------------------------------------------------------------
CBufferedStream::CBufferedStream(const char *filename) : fd_(open(filename, O_RDONLY | O_LARGEFILE))
{
	if(fd_<0) throw runtime_error(strerror(errno));

	pos_ = 0;

	rbuf_size_ = MAX_STREAM_BUF_SIZE;

	setg(buffer_,buffer_,buffer_);

	struct stat st;
	fstat(fd_,&st);

	fsize_ = st.st_size;
}
//---------------------------------------------------------------------------
CBufferedStream::CBufferedStream(const CBufferedStream &rhs)
{
	pos_ = rhs.pos_;
	fd_ = rhs.fd_;
	fsize_ = rhs.fsize_;
}
//---------------------------------------------------------------------------
CBufferedStream &CBufferedStream::operator=(const CBufferedStream &rhs) 
{
	pos_ = rhs.pos_;
	fd_ = rhs.fd_;
	fsize_ = rhs.fsize_;

	return *this;
}
//---------------------------------------------------------------------------
CBufferedStream::~CBufferedStream()
{
	close(fd_);
}
//---------------------------------------------------------------------------
int CBufferedStream::underflow()
{
	if(gptr()<egptr()) {
		return *gptr();
	}

	int size = read(fd_, buffer_, rbuf_size_);

	if(size) {
		pos_ += size;

		setg(buffer_, buffer_, buffer_+size);

		return *gptr();
	}
	
	pos_ = fsize_;
	return EOF;
}
//---------------------------------------------------------------------------
streambuf::pos_type CBufferedStream::seekoff(streambuf::off_type offset, ios::seekdir dir, ios::openmode)
{
	pos_type pos = lseek(fd_,offset,(dir==ios::beg)?SEEK_SET:(dir==ios::cur)?SEEK_CUR:SEEK_END);

	pos += (gptr() - egptr());

	if(pos<0) return -1;
    
	setg(buffer_, buffer_+1, buffer_+1);
	return pos;
}
//---------------------------------------------------------------------------
streambuf::pos_type CBufferedStream::seekpos(streambuf::pos_type offset, ios::openmode mode)
{
	return seekoff(offset, ios::beg, mode);
}
//---------------------------------------------------------------------------
uint64_t CBufferedStream::seekg(uint64_t pos)
{
	lseek(fd_,pos,SEEK_SET);

	pos_ = pos;

	setg(buffer_, buffer_, buffer_);

	return pos;
}
//---------------------------------------------------------------------------
uint64_t CBufferedStream::tellg() 
{
	return pos_ + (gptr() - egptr());
}
//---------------------------------------------------------------------------
uint64_t CBufferedStream::size() const 
{
	return fsize_;
}
//---------------------------------------------------------------------------
void CBufferedStream::resize(int buf_size)
{
	if(buf_size>MAX_STREAM_BUF_SIZE) {
		cerr << "the size of stream buffer cannot be grown more than " << MAX_STREAM_BUF_SIZE << endl;
		rbuf_size_ = MAX_STREAM_BUF_SIZE;
	}
	else rbuf_size_ = buf_size;
}
//---------------------------------------------------------------------------
